package com.mryan.aop_mylog.utils;

import com.mryan.aop_mylog.pojo.User;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.logging.Logger;

/**
 * @description： 切面
 * @Author MRyan
 * @Date 2021/1/6 15:06
 * @Version 1.0
 */
@Aspect
@Component
public class MyLogAspect {

    private static Logger logger = Logger.getLogger("MyLogAspect.class");


    /**
     * Controller层切点 设置操作日志切入点 记录操作日志 在注解的位置切入代码 扫描所有controller包下操作
     * <p>
     * //表示匹配所有方法
     * 1）execution(* *(..))
     * <p>
     * //表示匹配com.mryan.aop_mylog.controller中所有的公有方法
     * 2）execution(public * com.mryan.aop_mylog.controller.*(..))
     * <p>
     * //表示匹配com.mryan.aop_mylog.controller包及其子包下的所有方法
     * 3）execution(* com.mryan.aop_mylog.controller..*.*(..))
     */
    @Pointcut("execution (* com.mryan.aop_mylog.controller..*.*(..))")
    public void controllerAspect() {
    }

    /**
     * 等同于 @Before("execution (* com.mryan.aop_mylog.controller..*(..))")
     */
    @Before("controllerAspect()")
    public void before() {
        logger.info("--------------------Before--------------------");
    }


    /**
     * 配置controller环绕通知,使用在方法aspect()上注册的切入点  环绕通知=前置+目标方法执行+后置通知，proceed方法就是用于启动目标方法执行的
     *
     * @param point JointPoint是程序运行过程中可识别的点，这个点可以用来作为AOP切入点。JointPoint对象则包含了和切入相关的很多信息。比如切入点的对象，方法，属性等。我们可以通过反射的方式获取这些点的状态和信息，用于追踪tracing和记录logging应用信息。
     *              Proceedingjoinpoint 继承了 JoinPoint。是在JoinPoint的基础上暴露出 proceed 这个方法。proceed很重要，这个是aop代理链执行的方法。
     * @param myLog
     * @throws Throwable
     */
    @Around(value = "@annotation(myLog)")
    public void interceptorMyLog(ProceedingJoinPoint point, MyLog myLog) throws Throwable {
        logger.info("--------------------Around Before--------------------");
        //环绕通知  前置通知
        logger.info(point.getSignature().getDeclaringTypeName());
        logger.info(point.getSignature().getName());
        logger.info(String.valueOf(point.getSignature().getDeclaringType()));
        logger.info(point.getTarget().getClass().getName());
        logger.info(" ");
        Signature signature = point.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        logger.info(method.getName());
        //根据对象方法Methon获取修饰的注解，取得注解参数信息
        MyLog annotation = method.getAnnotation(MyLog.class);
        logger.info(annotation.myModul());
        logger.info(annotation.myrDesc());
        logger.info(annotation.myType());
        logger.info(" ");
        logger.info(myLog.myModul());
        logger.info(myLog.myrDesc());
        logger.info(myLog.myType());
        logger.info("日志已存入数据库中");
        //获取controller 方法传入参数
        Object[] args = point.getArgs();
        logger.info(Arrays.toString(args));


        logger.info("--------------------Around Proceed--------------------");
        //执行 调用方法  目标方法执行
        point.proceed();


        //环绕通知 后置 通知
        logger.info("--------------------Around after--------------------");
    }

    @After("controllerAspect()")
    public void after() {
        logger.info("--------------------after--------------------");
    }


    @AfterReturning("controllerAspect()")
    public void afterReturning() {
        logger.info("--------------------afterReturning--------------------");
    }

}
